package com.blue.jdbc;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.blue.core.id.SnowflakeId;
import org.springframework.jdbc.support.KeyHolder;

import com.blue.core.dict.annotation.DictParser;
import com.blue.core.id.IdGenerator;
import com.blue.jdbc.annotation.CacheColumn;
import com.blue.jdbc.annotation.CacheEntity;
import com.blue.jdbc.annotation.CacheId;
import com.blue.jdbc.annotation.CacheVersion;
import com.blue.jdbc.annotation.GeneratorType;
import com.blue.jdbc.annotation.IdType;
import com.blue.jdbc.annotation.Parser;

/**
 * 对象支持类
 * 
 * @author zhengj
 * @since 1.0 2011-4-1
 */
public class ObjectSupport
{
	private static ObjectSupport support = new ObjectSupport();

	private Parser parser = Parser.getInstance();
	private DictParser dictParser = DictParser.getInstance();
	private SnowflakeId snowflakeId;

	private ObjectSupport()
	{
	}
	
	public static ObjectSupport getInstance()
	{
		return support;
	}

	/**
	 * 产生主键
	 * 
	 * @param map 映射
	 * @param clazz 类型
	 */
	public void generateId(Map<String, Object> map, Class<?> clazz)
	{
		CacheEntity cacheEntity = parser.parse(clazz);
		for (Map.Entry<String, CacheId> entry : cacheEntity.getIdMap().entrySet())
		{
			CacheId id = entry.getValue();
			if (id.getGeneratorType() == GeneratorType.UUID)
			{
				if (id.getIdType() == IdType.STRING)
				{
					String uuid = IdGenerator.uuid32bit();
					map.put(id.getName(), uuid);
				}
				else if (id.getIdType() == IdType.LONG)
				{
					if (snowflakeId == null)
					{
						map.put(id.getName(), IdGenerator.id());
					}
					else
					{
						map.put(id.getName(), snowflakeId.nextId());
					}
				}
			}
		}
	}
	
	/**
	 * 取得对象的主键
	 * 
	 * @param obj 对象实例
	 * @return 映射
	 */
	public Map<String, Object> getId(Object obj)
	{
		Map<String, Object> map = new HashMap<>();
		CacheEntity cacheEntity = parser.parse(obj.getClass());
		for (Map.Entry<String, CacheId> entry : cacheEntity.getIdMap().entrySet())
		{
			CacheId id = entry.getValue();
			try
			{
				Method getter = id.getGetterMethod();
				map.put(id.getName(), getter.invoke(obj));
			}
			catch (Exception e)
			{
				throw new IllegalArgumentException(e);
			}
		}
		
		return map;
	}

	/**
	 * 设置对象主键
	 * 
	 * @param key
	 * @param object
	 */
	public void setId(KeyHolder key, Object object)
	{
		CacheEntity cacheEntity = parser.parse(object.getClass());
		for (Map.Entry<String, CacheId> entry : cacheEntity.getIdMap().entrySet())
		{
			CacheId id = entry.getValue();
			try
			{
				if (id.getGeneratorType() == GeneratorType.INCREMENT)
				{
					Method setter = id.getSetterMethod();
					Number nid = key.getKey();
					if (id.getIdType() == IdType.LONG)
						setter.invoke(object, nid.longValue());
					else if (id.getIdType() == IdType.INT)
						setter.invoke(object, nid.intValue());
				}
			}
			catch (Exception e)
			{
				throw new IllegalArgumentException(e);
			}
		}
		
	}

	/**
	 * 设置映射主键
	 * 
	 * @param key
	 * @param map
	 * @param clazz
	 */
	public void setId(KeyHolder key, Map<String, Object> map, Class<?> clazz)
	{
		CacheEntity cacheEntity = parser.parse(clazz);
		for (Map.Entry<String, CacheId> entry : cacheEntity.getIdMap().entrySet())
		{
			CacheId id = entry.getValue();
			if (id.getGeneratorType() == GeneratorType.INCREMENT)
			{
				Number nid = key.getKey();
				if (id.getIdType() == IdType.LONG)
					map.put(id.getName(), nid.longValue());
				else if (id.getIdType() == IdType.INT)
					map.put(id.getName(), nid.intValue());
			}
		}
	}

	/**
	 * 对象转换为映射
	 * 
	 * @param map
	 * @param object
	 */
	public void objectToMap(Map<String, Object> map, Object object, boolean update)
	{
		if (object == null)
			return;

		CacheEntity cacheEntity = parser.parse(object.getClass());
		try
		{
			for (Map.Entry<String, CacheId> entry : cacheEntity.getIdMap().entrySet())
			{
				CacheId cacheId = entry.getValue();
				GeneratorType type = cacheId.getGeneratorType();
				if (update && type == GeneratorType.INCREMENT)
					continue;
				
				Method getter = cacheId.getGetterMethod();
				Object val = this.convert(getter.invoke(object));

				if ("".equals(val))
					val = null;

				map.put(cacheId.getName(), val);
			}
			
			for (Map.Entry<String, CacheColumn> entry : cacheEntity.getColumnMap().entrySet())
			{
				CacheColumn cacheColumn = entry.getValue();
				Method getter = cacheColumn.getGetterMethod();
				Object val = this.convert(getter.invoke(object));

				if ("".equals(val))
					val = null;

				map.put(cacheColumn.getName(), val);
			}
			
			for (Map.Entry<String, CacheColumn> entry : cacheEntity.getExtraMap().entrySet())
			{
				CacheColumn cacheColumn = entry.getValue();
				Method getter = cacheColumn.getGetterMethod();
				Object val = this.convert(getter.invoke(object));

				if ("".equals(val))
					val = null;

				map.put(cacheColumn.getName(), val);
			}
			CacheVersion cacheVersion = cacheEntity.getVersion();
			if (cacheVersion != null)
			{
				Method getter = cacheVersion.getGetterMethod();
				Object val = getter.invoke(object);
				
				if (update && val == null)
					val = 1;
				
				map.put(cacheVersion.getName(), val);
			}
		}
		catch (Exception e)
		{
			throw new IllegalArgumentException(e);
		}
	}

	private Object convert(Object val)
	{
		if (val == null)
			return null;
		
		Class<?> clazz = val.getClass();
		if (clazz.isEnum())
			return dictParser.getFromObject(val);
		
		return val;
	}

	public void setSnowflakeId(SnowflakeId snowflakeId)
	{
		this.snowflakeId = snowflakeId;
	}
}
